package cn.nxcoder.blog.controller.admin;

import cn.nxcoder.blog.entity.Blog;
import cn.nxcoder.blog.entity.Tag;
import cn.nxcoder.blog.entity.Type;
import cn.nxcoder.blog.entity.User;
import cn.nxcoder.blog.model.BlogQuery;
import cn.nxcoder.blog.model.BlogVo;
import cn.nxcoder.blog.model.Page;
import cn.nxcoder.blog.service.BlogService;
import cn.nxcoder.blog.service.TagService;
import cn.nxcoder.blog.service.TypeService;
import com.github.pagehelper.PageHelper;
import com.vdurmont.emoji.EmojiParser;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 后台博客Controller
 * @author shengwu ni
 * @date 2018/05/05 11:48
 */
@Controller
@RequestMapping("/admin")
public class BlogController {

    @Resource
    private BlogService blogService;
    @Resource
    private TypeService typeService;
    @Resource
    private TagService tagService;

    /**
     * 按条件获取博客列表
     * @return String
     */
    @GetMapping("/blogs")
    public String list(@RequestParam(defaultValue = "1") Integer page, Model model) {

        // 每页显示5条记录
        PageHelper.startPage(page, 20);
        // 根据条件查出5条记录
        List<Blog> all = blogService.findAllByUpdateTimeDesc();
        Page<Blog> pageInfo = new Page<>(all);
        List<BlogVo> blogInfoList = getBlogInfoList(all);
        pageInfo.setBlogList(blogInfoList);
        model.addAttribute("page", pageInfo);
        model.addAttribute("types", typeService.findAll());

        return "admin/blogs";
    }

    /**
     * 用来局部更新博客列表中翻页信息
     * @param page 页数
     * @param blog blog
     * @param model model
     * @return String
     */
    @PostMapping("/blogs/search")
    public String search(@RequestParam(defaultValue = "1") Integer page,
                         BlogQuery blog, Model model) {

        // 每页显示20条记录
        PageHelper.startPage(page, 20);

        // 根据条件查出20条记录
        List<Blog> all = findAllByExample(blog);
        Page<Blog> pageInfo = new Page<>(all);
        List<BlogVo> blogInfoList = getBlogInfoList(all);
        pageInfo.setBlogList(blogInfoList);
        model.addAttribute("page", pageInfo);

        // 只更新博客列表部分的内容，上面搜索的东西不变，在thymeleaf模板中会定义一个blogList片段
        return "admin/blogs :: blogList";
    }

    private List<Blog> findAllByExample(BlogQuery blog) {
        Example example = new Example(Blog.class);
        Example.Criteria criteria = example.createCriteria();
        if (blog.getTitle() != null && !"".equals(blog.getTitle())) {
            criteria.andLike("title", "%" + blog.getTitle() + "%");
        }
        if (blog.getTypeid() != null) {
            criteria.andEqualTo("typeid", blog.getTypeid());
        }
        if (blog.isRecommend()) {
            criteria.andEqualTo("recommend", 1);
        } else {
            criteria.andEqualTo("recommend", 0);
        }
        if (blog.isPublished()) {
            criteria.andEqualTo("published", 1);
        } else {
            criteria.andEqualTo("published", 0);
        }
        return blogService.selectByExample(example);
    }

    private List<BlogVo> getBlogInfoList(List<Blog> list) {

        List<BlogVo> blogInfoList = new ArrayList<>();

        // 将博客所属的类别对象封装进去
        if (list != null && list.size() > 0) {
            list.forEach((b) -> {
                BlogVo blogVo = new BlogVo();
                BeanUtils.copyProperties(b, blogVo);
                Long typeid = b.getTypeid();
                Type type = typeService.findById(typeid);
                blogVo.setType(type);
                blogVo.setUpdate(new SimpleDateFormat("yyyy-MM-dd HH:mm").format(b.getUpdateTime()));
                blogInfoList.add(blogVo);
            });
        }
        return blogInfoList;
    }

    /**
     * 新增博客跳转接口
     * @return String
     */
    @GetMapping("/blogs/input")
    public String input(Model model) {
        model.addAttribute("blog", new Blog());
        model.addAttribute("types", typeService.findAll());
        model.addAttribute("tags", tagService.findAll());
        return "admin/blogs-input";
    }

    /**
     * 新增或更新博客
     * @param blog 博客实体，需要校验的
     * @param result 校验的结果
     * @param attributes 用于重定向带数据到前端
     * @return String
     */
    @PostMapping("/addOrUpdateBlogs")
    public String post(@Valid Blog blog, BindingResult result, HttpSession session, RedirectAttributes attributes) {

        User user = (User) session.getAttribute("user");
        blog.setUserid(user.getId());


        Integer r;
        // 插入
        if (blog.getId() == null) {

            // 业务上校验，新增的博客标题不能和已有的重复
            Blog blogByTitle = blogService.findBy("title", blog.getTitle());
            if (blogByTitle != null) {
                result.rejectValue("title", "titleError", "该博客标题已经存在，请换个标题");
                return "/admin/blogs-input";
            }

            blog.setCreateTime(new Date());
            blog.setUpdateTime(new Date());
            blog.setViews(0);
            // 将博客内容中的emoji表情转换一下，否则入库会报错。
            String tmpContent = EmojiParser.parseToAliases(blog.getContent());
            blog.setContent(tmpContent);
            r = blogService.save(blog);
            // 根据tagid将不同tag中的blogid设置好
            writeBlogIdToTags(blog, null);

        } else { // 更新
            // 先查出该博客当前都有哪些标签
            String tagidOld = blogService.findById(blog.getId()).getTagid();
            blog.setUpdateTime(new Date());
            // 将博客内容中的emoji表情转换一下，否则入库会报错。
            String tmpContent = EmojiParser.parseToAliases(blog.getContent());
            blog.setContent(tmpContent);
            r = blogService.update(blog);
            // 根据tagid将不同tag中的blogid设置好
            writeBlogIdToTags(blog, tagidOld);
        }

        // 对插入数据库的操作进行校验，验证是否正常插入或更新了
        if (r == null) {
            attributes.addFlashAttribute("message", "操作失败");
        } else {
            attributes.addFlashAttribute("message", "操作成功");
        }
        return "redirect:/admin/blogs";
    }

    private void writeBlogIdToTags(Blog blog, String tagidOld) {

        List<Tag> tagList = new ArrayList<>();
        if (blog.getTagid() != null && !"".equals(blog.getTagid())) {
            tagList = tagService.findByIds(blog.getTagid());
        }

        // 用来存储tagList中每个tag对应的id
        List<String> tagIdList = new ArrayList<>();

        // 以新标签为准添加blogid
        if (tagList != null && tagList.size() > 0) {
            tagList.forEach((tag) -> {
                String blogid = tag.getBlogid();
                if (blogid != null && !"".equals(blogid)) {
                    // 先判断该tag下是否已经有该博客了
                    if (!(blogid.contains(blog.getId() + "")
                       || blogid.contains(blog.getId() + ",")
                       || blogid.contains("," + blog.getId())
                       || blogid.contains("," + blog.getId() + ","))) {
                        tag.setBlogid(tag.getBlogid() + "," + blog.getId());
                    }
                } else {
                    tag.setBlogid(blog.getId() + "");
                }
                tagIdList.add(tag.getId() + "");
                tagService.update(tag);
            });
        }

        // 以旧标签为准删除blogid
        if (tagidOld != null && !"".equals(tagidOld)) {
            String[] oldTags = tagidOld.split(",");
            for (String oldTag : oldTags) {
                // 将被删掉的那个标签对应的博客id也去除
                if (!tagIdList.contains(oldTag)) {
                    Tag tag = tagService.findById(Long.valueOf(oldTag));
                    String blogids = tag.getBlogid();
                    tag.setBlogid(checkBlogIds(blogids, blog));
                    tagService.update(tag);
                }
            }
        }

    }

    private String checkBlogIds(String blogids, Blog blog) {
        if (blogids.contains("," + blog.getId() + ",")) {
            blogids = blogids.replace("," + blog.getId() + ",", ",");
        } else if (blogids.contains("," + blog.getId())) {
            blogids = blogids.replace("," + blog.getId(), "");
        } else if (blogids.contains(blog.getId() + ",")) {
            blogids = blogids.replace(blog.getId() + ",", "");
        } else if (blogids.equals(blog.getId() + "")) {
            blogids = "";
        } else {

        }
        return blogids;
    }

    /**
     * 编辑博客
     * @param id 博客id
     * @param model 将查询到的博客实体带到前端
     * @return String
     */
    @GetMapping("/blogs/{id}/input")
    public String editInput(@PathVariable Long id, Model model) {
        Blog blog = blogService.findById(id);
        model.addAttribute("blog", blog);
        model.addAttribute("types", typeService.findAll());
        model.addAttribute("tags", tagService.findAll());
        return "admin/blogs-input";
    }

    /**
     * 删除博客
     * @param id 博客id
     * @param attributes 用于重定向带数据到前端
     * @return
     */
    @GetMapping("/blogs/{id}/delete")
    public String delete(@PathVariable Long id, RedirectAttributes attributes) {
        // 先获取该博客对应的标签
        Blog blog = blogService.findById(id);
        String tagids = blog.getTagid();
        if (tagids != null && !"".equals(tagids)) {
            // 在对应的标签里删掉该博客信息
            for (String tagid : tagids.split(",")) {
                Tag tag = tagService.findById(Long.valueOf(tagid));
                String blogids = tag.getBlogid();
                if (blogids != null && !"".equals(blogids)) {
                    tag.setBlogid(checkBlogIds(blogids, blog));
                    tagService.update(tag);
                }
            }
        }
        // 若该博客没有标签，则直接删除
        Integer res = blogService.deleteById(id);
        if (res != null) {
            attributes.addFlashAttribute("message", "操作成功");
        } else {
            attributes.addFlashAttribute("message", "操作失败");
        }
        return "redirect:/admin/blogs";
    }
}
